home *** CD-ROM | disk | FTP | other *** search
/ IRIS Performer 2.2 Friends Demo / SGI IRIS Performer 2.2 Friends Demo.iso / friends / medit / pfLoader / Internalstuff / fileops.c < prev    next >
Text File  |  1997-11-20  |  23KB  |  940 lines

  1. /************************************************************************
  2. Subroutines for reading/writing files
  3. ************************************************************************/
  4.  
  5. /* File format revision */
  6. #define FileRevision 411
  7.  
  8. flag    AsciiMode = FALSE;  /* Might do this one day... */
  9. char    FileLine[1000], *LineData;
  10.  
  11. /************************************************************************
  12. Global vars/forward references
  13. ************************************************************************/
  14. static float Compatibility;    /* File version            */
  15. static flag byteswapped = FALSE;
  16. static int  MatListSize = 0,    /* Size of lists below...    */
  17.         TexListSize = 0;
  18. static TexturePtr *TextureList;
  19. static MaterialPtr *MaterialList;
  20. static TexturePtr LastTexture;
  21. static MaterialPtr LastMaterial;
  22. static unsigned int LastPolyColour, LastVertexColour;
  23.  
  24. #if ITSTHEMODELLER
  25. static void DealWithSceneView(reg int id, reg ViewPtr view);
  26. #endif
  27.  
  28. /************************************************************************
  29. Read/write bytes...
  30. ************************************************************************/
  31. static boolean PutByte(reg FILE *f, reg int b)
  32. {
  33.     if (!FileError) {
  34.     if (fputc(b,f) IS EOF) {
  35.         SetError(-1);
  36.         return FALSE;
  37.     }
  38.     return TRUE;    /* Ok */
  39.     }
  40.     else {
  41.     return FALSE;
  42.     }
  43. }
  44. static boolean GetByte(reg FILE *f, reg int *Result)
  45. {
  46.     if (!FileError) {
  47.     if ((*Result = fgetc(f)) IS EOF) {
  48.         SetError(REACHED_END);
  49.         return FALSE;
  50.     }
  51.     return TRUE;    /* Ok */
  52.     }
  53.     else {
  54.     return FALSE;
  55.     }
  56. }
  57. /************************************************************************
  58. Read/write a data token...
  59. ************************************************************************/
  60. static boolean PutToken(reg FILE *f, reg int token)
  61. {
  62.     if (AsciiMode) {
  63.     if (fprintf(f, "\n%s", TokenList[token]) ISNT -1) {
  64.         return TRUE;
  65.     }
  66.     return FALSE;
  67.     }
  68.     else {
  69.     while (token > 254) {
  70.         if (!PutByte(f, 255)) {
  71.         return FALSE;
  72.         }
  73.         token -= 254;
  74.     }
  75.     return PutByte(f, token);
  76.     }
  77. }
  78. static boolean GetToken(reg FILE *f, reg int *Result)
  79. {
  80.     int t;
  81.     reg int c, n;
  82.     reg flag FoundData;
  83.     reg char *l, *d;
  84.     if (AsciiMode) {
  85.     n = 0;
  86.     l = FileLine;
  87.     FoundData = FALSE;
  88.     do {
  89.         if ((c = fgetc(f)) IS EOF) {
  90.         SetError(REACHED_END);
  91.         return FALSE;
  92.         }
  93.         if ((c ISNT '\n') AND (n < 999)) {
  94.         *l++ = c;
  95.         if ((c IS ' ') AND !FoundData) {
  96.             d = l;
  97.         }
  98.         }
  99.     } until (c IS '\n');
  100.     *l++ = '\0';
  101.     LineData = d;
  102.     return TRUE;
  103.     }
  104.     else {
  105.     if (!GetByte(f, &t)) {
  106.         return FALSE;
  107.     }
  108.     n = t;
  109.     while (t IS 255) {
  110.         n--;
  111.         if (!GetByte(f, &t)) {
  112.         return FALSE;
  113.         }
  114.         n += t;
  115.     }
  116.     *Result = n;
  117.     return TRUE;
  118.     }
  119. }
  120. /************************************************************************
  121. Byte swap a word of data
  122. ************************************************************************/
  123. static void ByteSwap(void *word)
  124. {
  125.     reg unsigned char t, *w = (unsigned char*)word;
  126.     t = w[0]; w[0] = w[3]; w[3] = t;
  127.     t = w[1]; w[1] = w[2]; w[2] = t;
  128. }
  129. /************************************************************************
  130. Read/write integers...
  131. ************************************************************************/
  132. static boolean PutInt(reg FILE *f, int i)
  133. {
  134.     if (!FileError) {
  135.     if (fwrite(&i, sizeof(int), 1, f) ISNT 1) {
  136.         SetError(-1);
  137.         return FALSE;
  138.     }
  139.     else {
  140.         return TRUE;    /* Ok */
  141.     }
  142.     }
  143.     else {
  144.     return FALSE;
  145.     }
  146. }
  147. static boolean GetInt(reg FILE *f, reg int *Result)
  148. {
  149.     if (!FileError) {
  150.     if (fread(Result, sizeof(int), 1, f) ISNT 1) {
  151.         SetError(BAD_FILE);
  152.         return FALSE;
  153.     }
  154.     if (byteswapped) {
  155.         ByteSwap(Result);
  156.     }
  157.     return TRUE;    /* Not really ok, but fast and harmless */
  158.     }
  159.     else {
  160.     return FALSE;
  161.     }
  162. }
  163. /************************************************************************
  164. Read/write floats...
  165. ************************************************************************/
  166. static boolean PutFloats(reg FILE *f, reg float *r, reg unsigned int no)
  167. {
  168.     if (!FileError) {
  169.     if (fwrite(r,sizeof(float),no,f) ISNT no) {
  170.         SetError(-1);
  171.         return FALSE;
  172.     }
  173.     else {
  174.         return TRUE;    /* Ok */
  175.     }
  176.     }
  177.     else {
  178.     return FALSE;
  179.     }
  180. }
  181. static boolean GetFloats(reg FILE *f, reg float *Result, reg unsigned int no)
  182. {
  183.     reg unsigned int i;
  184.  
  185.     if (!FileError) {
  186.     if (fread(Result,sizeof(float),no,f) ISNT no) {
  187.         SetError(BAD_FILE);
  188.         return FALSE;
  189.     }
  190.     else {
  191.         if (byteswapped) {
  192.         for (i=0; i<no; i++) {
  193.             ByteSwap(Result+i);
  194.         }
  195.         }
  196.         return TRUE;    /* Ok */
  197.     }
  198.     }
  199.     else {
  200.     return FALSE;
  201.     }
  202. }
  203. /************************************************************************
  204. Read/write reals...
  205. ************************************************************************/
  206. static boolean PutReals(reg FILE *f, reg real *r, reg unsigned int no)
  207. {
  208.     if (!FileError) {
  209.     if (fwrite(r,sizeof(real),no,f) ISNT no) {
  210.         SetError(-1);
  211.         return FALSE;
  212.     }
  213.     else {
  214.         return TRUE;    /* Ok */
  215.     }
  216.     }
  217.     else {
  218.     return FALSE;
  219.     }
  220. }
  221. #define MaxRealBlock 16
  222. static boolean GetReals(reg FILE *f, reg real *Result, reg unsigned int no)
  223. {
  224.     reg unsigned int i, t, *d;
  225.     float workspace[MaxRealBlock];
  226.  
  227.     if (!FileError) {
  228.     if (Compatibility < 4.01) {
  229.         if (GetFloats(f,workspace,no)) {
  230.         reg unsigned int i;
  231.         reg real *rp = Result;
  232.         reg float *fp = workspace;
  233.         for (i=0; i<no; i++) {
  234.             *rp++ = *fp++;
  235.         }
  236.         return TRUE;    /* Ok */
  237.         }
  238.         else {
  239.         return FALSE;
  240.         }
  241.     }
  242.     else {
  243.         if (fread(Result,sizeof(real),no,f) ISNT no) {
  244.         SetError(BAD_FILE);
  245.         return FALSE;
  246.         }
  247.         else {
  248.         if (byteswapped) {
  249.             for (i=0; i<no; i++) {
  250.             d = (unsigned int*)Result;
  251.             t = d[0];
  252.             d[0] = d[1];
  253.             d[1] = t;
  254.             ByteSwap(d);
  255.             ByteSwap(d+1);
  256.             Result++;
  257.             }
  258.         }
  259.         return TRUE;    /* Ok */
  260.         }
  261.     }
  262.     }
  263.     else {
  264.     return FALSE;
  265.     }
  266. }
  267. #undef MaxRealBlock
  268. /************************************************************************
  269. Read/write strings...
  270. ************************************************************************/
  271. static boolean PutString(FILE *f, char *s)
  272. {
  273.     if (!FileError) {
  274.     while (*s ISNT '\0') {
  275.         ifbad (PutByte(f,*s++)) {
  276.         return FALSE;
  277.         }
  278.     }
  279.     ifbad (PutByte(f,'\n')) {
  280.         return FALSE;
  281.     }
  282.     return TRUE;            /* Ok */
  283.     }
  284.     else {
  285.     return FALSE;
  286.     }
  287. }
  288. static boolean GetString(FILE *f, reg char *Result, reg int MaxChars)
  289. {
  290.     if (!FileError) {
  291.     int c;
  292.     reg int i;
  293.     if (!fgets(Result,MaxChars,f)) {
  294.         SetError(BAD_STRING);
  295.         return FALSE;
  296.     }
  297.     for (i=0; i<MaxChars; i++) {
  298.         if (Result[i] IS '\n') {
  299.         Result[i] = '\0';
  300.         return TRUE;
  301.         }
  302.     }
  303.     while (GetByte(f, &c)) {
  304.         if (c IS '\n') {
  305.         return TRUE;
  306.         }
  307.     }
  308.     }
  309.     return FALSE;
  310. }
  311. /************************************************************************
  312. Read/write sizes of things
  313. ************************************************************************/
  314. static void PutSize(FILE *f, int size)
  315. {
  316.     if (size > 255) {
  317.     PutByte(f,0);
  318.     PutInt(f,size);
  319.     }
  320.     else {
  321.     PutByte(f,size);
  322.     }
  323. }
  324. static boolean GetSize(reg FILE *f, reg int *n)
  325. {
  326.     ifbad(GetByte(f,n)) return FALSE;
  327.     if (*n IS 0) {
  328.     ifbad(GetInt(f,n)) return FALSE;
  329.     }
  330.     return TRUE;
  331. }
  332. static void PutSizedInt(reg FILE *f, int i)
  333. {
  334.     PutSize(f, sizeof(int));
  335.     PutInt(f, i);
  336. }
  337. static boolean GetSizedInt(reg FILE *f, int *i)
  338. {
  339.     int s;
  340.     if (!GetSize(f, &s) OR (s ISNT sizeof(int))) {
  341.     return FALSE;
  342.     }
  343.     return GetInt(f, i);
  344. }
  345. /************************************************************************
  346. Skip unknown data
  347. ************************************************************************/
  348. static boolean SkipData(reg FILE *f, reg int bytes)
  349. {
  350.     int i,trash;
  351.     for (i=0; i<bytes; i++) {
  352.     ifbad(GetByte(f,&trash)) return FALSE;
  353.     }
  354.     return TRUE;
  355. }
  356. static boolean SkipFuture(reg FILE *f)
  357. {
  358.     int n;
  359.     ifbad(GetSize(f,&n)) return FALSE;    /* Suss size of data...        */
  360.     ifbad(SkipData(f,n)) return FALSE;    /* Skip that much        */
  361.     return TRUE;
  362. }
  363. /************************************************************************
  364. Change the coordinate system of pre 3.01 files
  365. ************************************************************************/
  366. static void TwistReal(reg real *n)
  367. {
  368.     if (Compatibility < 3.01) {
  369.     reg real temp = n[Y];
  370.     n[Y] = -n[Z];
  371.     n[Z] = temp;
  372.     }
  373. }
  374. static void TwistFloat(reg float *n)
  375. {
  376.     if (Compatibility < 3.01) {
  377.     reg float temp = n[Y];
  378.     n[Y] = -n[Z];
  379.     n[Z] = temp;
  380.     }
  381. }
  382. /************************************************************************
  383. Read/write a matrix
  384. ************************************************************************/
  385. static void PutMatrix(reg FILE *f, reg MatrixPtr m)
  386. {
  387.     if (!FileError) {
  388.     PutReals(f,m[X],4);
  389.     PutReals(f,m[Y],4);
  390.     PutReals(f,m[Z],4);
  391.     PutReals(f,m[W],4);
  392.     }
  393. }
  394. static boolean GetMatrix(reg FILE *f, reg MatrixPtr m)
  395. {
  396.     reg int i;
  397.     reg real temp;
  398.  
  399.     if (!GetReals(f,m[X],4)) return FALSE;
  400.     if (!GetReals(f,m[Y],4)) return FALSE;
  401.     if (!GetReals(f,m[Z],4)) return FALSE;
  402.     if (!GetReals(f,m[W],4)) return FALSE;
  403.  
  404.     if (Compatibility < 3.01) {
  405.     TwistReal(m[X]);
  406.     TwistReal(m[Y]);
  407.     TwistReal(m[Z]);
  408.     TwistReal(m[W]);
  409.     for (i=0; i<XYZ; i++) {
  410.         temp = m[Y][i];
  411.         m[Y][i] = -m[Z][i];
  412.         m[Z][i] = temp;
  413.     }
  414.     }
  415.     return TRUE;
  416. }
  417. /************************************************************************
  418. Write a string with its length
  419. ************************************************************************/
  420. static void WriteDataString(reg FILE *f, reg int token, reg char *string)
  421. {
  422.     PutToken(f,FData);
  423.     PutByte(f,token);
  424.     PutSize(f,strlen(string)+1);
  425.     PutString(f,string);
  426. }
  427.  
  428.  
  429.  
  430. /************************************************************************
  431. Patch up all the pointer references after loading the file
  432. ************************************************************************/
  433. static void ObjectReferencePatcher(rconst TreePtr t, rconst void *unused)
  434. {
  435.     reg int id;
  436.     reg ModelObjectPtr o;
  437.     if (t->Type IS InstanceBranch) {
  438.     id = t->ObjId;
  439.     LoopThroughAllObjects(o) {
  440.         if (o->Id IS id) {
  441.         t->Obj = o;
  442.         if ((Compatibility < 406) AND !strcmp(t->Name, "Object")) {
  443.             RenameBranch(t, o->Name);
  444.         }
  445.         break;
  446.         }
  447.     }
  448.     if (!o) {
  449.         SetError(BAD_OBJECT);
  450.     }
  451.     }
  452. }
  453. typedef struct { TreePtr connect; int id; } CFdata;
  454. static void ConnectionFinder(rconst TreePtr t, rconst void *con)
  455. {
  456.     reg CFdata *c = (CFdata*)con;
  457.     if (t->BranchId IS c->id) {
  458.     c->connect->Connection = t;
  459.     }
  460. }
  461. static void ConnectionPatcher(rconst TreePtr e, rconst void *o)
  462. {
  463.     CFdata c;
  464.     e->Connection = NULL;
  465.     if (e->ConnectId ISNT -1) {
  466.     c.connect = e;
  467.     c.id = e->ConnectId;
  468.     ScanTree(((ModelObjectPtr)o)->Tree, ConnectionFinder, &c);
  469.     if (!e->Connection) {
  470.         ScanTree(((ModelObjectPtr)o)->Engines, ConnectionFinder, &c);
  471.     }
  472.     }
  473. }
  474. static void PatchReferences(void)
  475. {
  476.     reg ModelObjectPtr o;
  477.     LoopThroughAllObjects(o) {
  478.     if (!o->External) {
  479.         ScanTree(o->Tree, ObjectReferencePatcher, NULL);
  480.     }
  481.     ScanTree(o->Engines, ConnectionPatcher, o);
  482.     }
  483. }
  484. /************************************************************************
  485. Read a view structure
  486. ************************************************************************/
  487. #if ITSTHEMODELLER
  488. static void ReadView(reg FILE *f)
  489. {
  490.     View v;
  491.     Matrix proj;
  492.     int id, token;
  493.     flag hadproj = FALSE;
  494.  
  495.     GetInt(f, &id);
  496.     v.HasCentreOfRotation = FALSE;
  497.     
  498.     while (GetToken(f, &token)) {
  499.     if (token IS BlockEnd) {
  500.         break;
  501.     }
  502.     else switch (token) {
  503.         case FViewThreeDee:        GetStuff(GetByte(f,&v.ThreeDee));
  504.                     break;
  505.         case FViewAxis:        GetStuff(GetByte(f,&v.Axis));
  506.                     break;
  507.         case FViewViewMatrix:   GetStuff(GetMatrix(f,v.ViewMatrix));
  508.                     break;
  509.         case FViewProjectMatrix:hadproj = TRUE;
  510.                     GetStuff(GetMatrix(f,proj));
  511.                     break;
  512.         case FViewGridMatrix:   GetStuff(GetMatrix(f,v.GridMatrix));
  513.                     break;
  514.         case FViewMagnification:GetStuff(GetReals(f,&v.Magnification,1));
  515.                     if (hadproj AND (Compatibility > 2.99)) {
  516.                     v.Magnification = 1.0/(v.Magnification*proj[Y][Y]);
  517.                     }
  518.                     break;
  519.         case FViewCOR:        v.HasCentreOfRotation = TRUE;
  520.                     GetStuff(GetReals(f,v.CentreOfRotation,3));
  521.                     break;
  522.         default:            if (!SkipFuture(f)) {
  523.                     SetError(BAD_VIEW);
  524.                     }
  525.     }
  526.     }
  527.     v.Valid = TRUE;
  528.     if ((id >= 0) AND (id < NoViews)) {            /* Object views */
  529.     CopyView(DefaultObject2D(id),&v);
  530.     }
  531.     else if (id IS 0x3d) {
  532.     CopyView(DefaultObject3D(),&v);
  533.     }
  534.     else if ((id >= 0x100) AND (id < (0x100+MaxViewports))) {
  535.     CopyView(ObjectView(id-0x100),&v);
  536.     }
  537.     else if ((id >= 0x180) AND (id < (0x188))) {
  538.     CopyView(UserView(id-0x180),&v);
  539.     }
  540.     else if (Compatibility < 4.0) {
  541.     DealWithSceneView(id, &v);
  542.     }
  543. }
  544. #else
  545. static void ReadView(reg FILE *f)
  546. {
  547.     int token;
  548.     real junk[16];
  549.     GetInt(f,&token);
  550.     while (GetToken(f, &token)) {
  551.     if (token IS BlockEnd) {
  552.         break;
  553.     }
  554.     else switch (token) {
  555.         case FViewThreeDee:        GetStuff(SkipData(f,1));    break;
  556.         case FViewAxis:        GetStuff(SkipData(f,1));    break;
  557.         case FViewViewMatrix:    GetStuff(GetReals(f,junk,16));    break;
  558.         case FViewProjectMatrix:    GetStuff(GetReals(f,junk,16));    break;
  559.         case FViewGridMatrix:    GetStuff(GetReals(f,junk,16));    break;
  560.         case FViewMagnification:    GetStuff(GetReals(f,junk,1));    break;
  561.         case FViewCOR:        GetStuff(GetReals(f,junk,3));    break;
  562.         default:            if (!SkipFuture(f)) {
  563.                         SetError(BAD_VIEW);
  564.                     }
  565.     }
  566.     }
  567. }
  568. #endif
  569.  
  570. /************************************************************************
  571. Bounding boxes...
  572. ************************************************************************/
  573. static void WriteBoundingBox(reg FILE *f, reg real *min, reg real *max)
  574. {
  575.     PutToken(f, FBoundingBox);
  576.     PutReals(f, min, 3);
  577.     PutReals(f, max, 3);
  578. }
  579. static void ReadBoundingBox(reg FILE *f, reg real *min, reg real *max)
  580. {
  581.     GetStuff(GetReals(f, min, 3));
  582.     GetStuff(GetReals(f, max, 3));
  583. }
  584. /************************************************************************
  585. Polygon interconnections
  586. ************************************************************************/
  587. static int VertexIndex;
  588. #if ITSTHEMODELLER
  589. void WritePolyConnections(FILE *f, TreePtr t)
  590. {
  591.     reg int i;
  592.     reg TmeshPtr tm;
  593.     reg PolygonPtr p;
  594.     reg PolygonBeadPtr pb;
  595.  
  596.     LoopThroughBranchesVertices(t, i) {
  597.     pb = t->Vertex[i];
  598.     PutByte(f, FVertexJoin);
  599.     while (pb) {
  600.         PutInt(f, pb->Temp);
  601.         pb = pb->Touch;
  602.     }
  603.     PutInt(f, -1);
  604.     }
  605.     p = t->Unmeshed;
  606.     if (p) {
  607.     PutByte(f, FUnmeshed);
  608.     while (p) {
  609.         PutInt(f, p->Flag);
  610.         p = p->Mesh;
  611.     }
  612.     PutInt(f, -1);
  613.     }
  614.     tm = t->Meshed;
  615.     while (tm) {
  616.     PutByte(f, FTmesh);
  617.     pb = tm->FirstBead;
  618.     while (pb) {
  619.         PutInt(f, pb->Temp);
  620.         pb = pb->Mesh;
  621.     }
  622.     PutInt(f, -1);
  623.     tm = tm->Next;
  624.     }
  625. }
  626. #endif
  627. static int VertexListSize = 0;
  628. static PolygonBeadPtr *VertexList = NULL;
  629. static void AddToVertexList(PolygonBeadPtr pb)
  630. {
  631.     while (VertexIndex >= VertexListSize) {
  632.     if (!VertexListSize) {
  633.         VertexListSize = 1024;
  634.         VertexList = malloc(VertexListSize*sizeof(PolygonBeadPtr));
  635.     }
  636.     else {
  637.         VertexListSize *= 2;
  638.         VertexList = realloc(VertexList, VertexListSize*sizeof(PolygonBeadPtr));
  639.     }
  640.     }
  641.     VertexList[VertexIndex++] = pb;
  642. }
  643. static int PolygonListSize = 0;
  644. static PolygonPtr *PolygonList = NULL;
  645. static void AddToPolygonList(PolygonPtr p)
  646. {
  647.     while (VertexIndex >= PolygonListSize) {
  648.     if (!PolygonListSize) {
  649.         PolygonListSize = 1024;
  650.         PolygonList = malloc(PolygonListSize*sizeof(PolygonPtr));
  651.     }
  652.     else {
  653.         PolygonListSize *= 2;
  654.         PolygonList = realloc(PolygonList, PolygonListSize*sizeof(PolygonPtr));
  655.     }
  656.     }
  657.     PolygonList[VertexIndex] = p;
  658. }
  659. static void ReadVertexJoin(FILE *f, TreePtr t)
  660. {
  661.     int index = 0;
  662.  
  663. #if ITSTHEMODELLER
  664.     reg PolygonBeadPtr pb, first, last = NULL;
  665.     if (t->NoVertices IS t->MaxVertices) {
  666.     t->MaxVertices += 1000;
  667.     if (t->NoVertices IS 0) {
  668.         t->Vertex = Allocate(t->MaxVertices*sizeof(PolygonBeadPtr));
  669.     }
  670.     else {
  671.         t->Vertex = Reallocate(t->Vertex, t->MaxVertices*sizeof(PolygonBeadPtr));
  672.     }
  673.     }
  674.     until (index IS -1) {
  675.     GetStuff(GetInt(f, &index));
  676.     if (index ISNT -1) {
  677.         pb = VertexList[index];
  678.         pb->Temp = index;
  679.         if (last) {
  680.         last->Touch = pb;
  681.         }
  682.         else {
  683.         first = pb;
  684.         t->Vertex[t->NoVertices++] = first;
  685.         }
  686.         last = pb;
  687.         last->FirstTouch = first;
  688.     }
  689.     }
  690.     if (last) {
  691.     last->Touch = NULL;
  692.     }
  693. #else
  694.     until (index IS -1) {
  695.     GetStuff(GetInt(f, &index));
  696.     }
  697. #endif
  698. }
  699. static void ReadUnmeshed(FILE *f, TreePtr t)
  700. {
  701.     int index = 0;
  702.     until (index IS -1) {
  703.     GetStuff(GetInt(f, &index));
  704.     }
  705. }
  706. static void ReadTmesh(FILE *f, TreePtr t)
  707. {
  708.     int lefty, index = 0;
  709.  
  710.     if (Compatibility < 411) {            /* Pre 411 files can have leftys */
  711.     GetStuff(GetInt(f, &lefty));
  712.     }
  713.     until (index IS -1) {
  714.     GetStuff(GetInt(f, &index));
  715.     }
  716. }
  717. /************************************************************************
  718. Go back up a level in the tree
  719. ************************************************************************/
  720. static TreePtr SearchForBranch(reg TreePtr t, reg TreePtr parent, reg TreePtr search)
  721. {
  722.     reg TreePtr found;
  723.     while (t) {
  724.     if (t->Across) {
  725.         if (found = SearchForBranch(t->Across, t, search)) {
  726.         return found;
  727.         }
  728.     }
  729.     if (t IS search) {
  730.         return parent;
  731.     }
  732.     t = t->Down;
  733.     }
  734.     return NULL;
  735. }
  736. static TreePtr GoUp(reg TreePtr start, reg TreePtr t)
  737. {
  738. #if ITSTHEMODELLER
  739.     while (t->Up) {    /* Easy in ModelWorks as we have more links */
  740.     t = t->Up;
  741.     }
  742.     t = t->Back;
  743. #else
  744.     t = SearchForBranch(start, NULL, t);
  745. #endif
  746.     return t;
  747. }
  748. /************************************************************************
  749. Read/write construction vertices
  750. ************************************************************************/
  751. static void WriteConstructionVertices(reg FILE *f, reg ModelObjectPtr o)
  752. {
  753.     reg PolygonBeadPtr pb = o->FirstConstructionVertex;
  754.     while (pb) {
  755.     PutByte(f, FVConstruction);
  756.     PutReals(f, pb->Position, XYZ);
  757.     pb = pb->Next;
  758.     }
  759. }
  760. static void ReadConstructionVertex(reg FILE *f, reg ModelObjectPtr o)
  761. {
  762.     reg PolygonBeadPtr pb;
  763.     pb = NewPolygonBead();
  764.     pb->Next = o->FirstConstructionVertex;
  765.     o->FirstConstructionVertex = pb;
  766.     GetStuff(GetReals(f, pb->Position, XYZ));
  767. }
  768. /************************************************************************
  769. Read an external file reference
  770. ************************************************************************/
  771. static void ReadExref(reg ModelObjectPtr o)
  772. {
  773.     reg char *name;
  774.     reg ModelFilePtr f;
  775.     reg ModelObjectPtr top;
  776.     
  777.     ExternalObject = o;
  778.     if (name = FindFile(o->File, NULL, FilePath, "objects")) {
  779.     Free(o->File);
  780.     o->File = CopyOfString(name);
  781.     if (f = LoadExternalFile(o->File)) {
  782.         o->External = f;
  783.         top = f->FirstObject;
  784.         while (top) {
  785.         if (top->IsTopLevel) {
  786.             break;
  787.         }
  788.         top = top->Next;
  789.         }
  790.         if (!top) {
  791.         top = f->FirstObject;
  792.         }
  793.         o->Tree = top->Tree;
  794.         o->Engines = top->Engines;
  795.     }    
  796.     }
  797. }
  798. /************************************************************************
  799. Read/write motion path data
  800. ************************************************************************/
  801. static void WritePathData(reg FILE *f, reg PathPtr p)
  802. {
  803.     reg int i, j;
  804.     reg PathBeadPtr b;
  805.     reg BezierDataPtr s;
  806.  
  807.     PutByte(f, FMotionPath);
  808.     b = p->FirstBead;
  809.     while (b) {
  810.     PutToken(f, FPathBead);        PutReals(f, b->Position, 3);
  811.     PutToken(f, FBeadRounded);    PutInt(f, b->Rounded);
  812.     PutToken(f, BlockEnd);
  813.     b = b->Next;
  814.     }
  815.     PutToken(f, FPathBasis);    PutInt(f, p->Basis);
  816.     PutToken(f, FPathClosed);    PutInt(f, p->Closed);
  817.     PutToken(f, FPathSmoothing);PutInt(f, p->Smoothing);
  818.  
  819. #if ITSTHEMODELLER
  820.     if (!p->Valid) {
  821.     p->Valid = TRUE;
  822.     GenerateBezierData(p);
  823.     }
  824. #endif
  825.     if (p->NoCurves > 0) {
  826.     PutToken(f, FBezierData);        PutInt(f, p->NoCurves);
  827.     PutToken(f, FBezierLength);        PutReals(f, &(p->CurveLength), 1);
  828.     PutToken(f, FHeadingOffset);        PutFloats(f, &(p->HeadingOffset), 1);
  829.     PutToken(f, FPitchOffset);        PutFloats(f, &(p->PitchOffset), 1);
  830.     for (i=0; i<p->NoCurves; i++) {
  831.         s = &(p->Curve[i]);
  832.         PutToken(f, FBezierSegment);    PutInt(f, i);
  833.         PutToken(f, FBezierStart);        PutReals(f, &(s->Start), 1);
  834.         PutToken(f, FBezierLength);        PutReals(f, &(s->Length), 1);
  835.         for (j=0; j<4; j++) {
  836.         PutToken(f, FControlPoint);    PutInt(f, j);
  837.         PutReals(f, s->ControlPoint[j], XYZ);
  838.         }
  839.         PutToken(f, FSegmentSize);        PutInt(f, s->Subdivision);
  840.         PutReals(f, s->l, s->Subdivision);
  841.         PutToken(f, BlockEnd);
  842.     }
  843.     }
  844.     PutToken(f, BlockEnd);
  845. }
  846. static void ReadBezierSegment(reg FILE *f, reg PathPtr p)
  847. {
  848.     int token, n;
  849.     reg flag done = FALSE;
  850.     reg BezierDataPtr s;
  851.  
  852.     GetStuff(GetInt(f, &n));
  853.     s = &(p->Curve[n]);
  854.     until (done OR !GetToken(f, &token)) {
  855.     switch (token) {
  856.         case BlockEnd:    return;
  857.  
  858.         case FBezierStart:    GetStuff(GetReals(f, &(s->Start), 1));
  859.                 break;
  860.         case FBezierLength:    GetStuff(GetReals(f, &(s->Length), 1));
  861.                 break;
  862.         case FControlPoint:    GetStuff(GetInt(f, &n));
  863.                 GetStuff(GetReals(f, s->ControlPoint[n], XYZ));
  864.                 break;
  865.         case FSegmentSize:    GetStuff(GetInt(f, &(s->Subdivision)));
  866. #if ITSTHEMODELLER
  867.                 s->MaxSubdivision = s->Subdivision;
  868. #endif
  869.                 s->l = Allocate(s->Subdivision * sizeof(real));
  870.                 GetStuff(GetReals(f, s->l, s->Subdivision));
  871.                 break;
  872.                    
  873.         default:        if (!SkipFuture(f)) {
  874.                     SetError(BAD_OBJECT);
  875.                 }
  876.     }
  877.     }   
  878. }
  879. static void ReadPathBead(reg FILE *f, reg PathBeadPtr pb)
  880. {
  881.     int token;
  882.     reg flag done = FALSE;
  883.  
  884.     until (done OR !GetToken(f, &token)) {
  885.     switch (token) {
  886.         case BlockEnd:    return;
  887.  
  888.         case FBeadRounded:    GetStuff(GetInt(f, &(pb->Rounded)));    break;
  889.  
  890.         default:        if (!SkipFuture(f)) {
  891.                     SetError(BAD_OBJECT);
  892.                 }
  893.     }
  894.     }
  895. }
  896. static void ReadPathData(reg FILE *f, reg PathPtr *p)
  897. {
  898.     int token;
  899.     Coordinate c;
  900.     reg PathPtr new;
  901.     reg flag done = FALSE, hadsegs = FALSE;
  902.  
  903.     *p = new = NewPath();
  904.     until (done OR !GetToken(f, &token)) {
  905.     switch (token) {
  906.         case BlockEnd:
  907. #if ITSTHEMODELLER
  908.                 if (hadsegs AND (Compatibility IS FileRevision)) {
  909.                     (*p)->Valid = FALSE;
  910.                 }
  911. #endif
  912.                 return;
  913.  
  914.         case FPathBead:    GetStuff(GetReals(f, c, 3));
  915.                 ReadPathBead(f, AddBeadToPathEnd(new, c));break;
  916.  
  917.         case FPathBasis:    GetStuff(GetInt(f, &(new->Basis)));    break;
  918.         case FPathClosed:    GetStuff(GetInt(f, &(new->Closed)));    break;
  919.         case FPathSmoothing:GetStuff(GetInt(f, &(new->Smoothing)));    break;
  920.         case FBezierData:    GetStuff(GetInt(f, &(new->NoCurves)));
  921. #if ITSTHEMODELLER
  922.                 new->MaxCurves = new->NoCurves;
  923. #endif
  924.                 new->Curve = Allocate(new->NoCurves * sizeof(BezierData));
  925.                                     break;
  926.         case FBezierLength:    GetStuff(GetReals(f, &(new->CurveLength), 1));
  927.                                     break;
  928.         case FHeadingOffset:GetStuff(GetFloats(f, &(new->HeadingOffset), 1));
  929.                                     break;
  930.         case FPitchOffset:    GetStuff(GetFloats(f, &(new->PitchOffset), 1));
  931.                                     break;
  932.         case FBezierSegment:hadsegs = TRUE;
  933.                 ReadBezierSegment(f, new);        break;
  934.         default:        if (!SkipFuture(f)) {
  935.                     SetError(BAD_OBJECT);
  936.                 }
  937.     }
  938.     }
  939. }
  940.